﻿////***************************************************************************************
//// StencilApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
////***************************************************************************************
//
///*  流水线状态对象（PSO = Pipeline State Object)
//    1.模板:
//        模板缓冲区（stencil buffer）是一种“离屏”（off-screen）缓冲区，我们可以利用它来实现一些特殊效果。
//        模板缓冲区、后台缓冲区以及深度缓冲区都有着相同的分辨率，这样一来，这三者相同位置上的像素就能一一对应起来。
//        回顾4.1.5节可知，在指定一个模板缓冲区时，要将它与一个深度缓冲区配合使用。
//        顾名思义，这种缓冲区所起到的作用就如同印刷过程中所用的模板一样，我们可以用它来阻止特定的像素片段渲染至后台缓冲区中。
//        要设置模板缓冲区（以及深度缓冲区）状态，就需填写D3D12_DEPTH_STENCIL_DESC结构体实例，
//        并将其赋予流水线状态对象（PSO = Pipeline State Object）的D3D12_GRAPHICS_PIPELINE_STATE_DESC::DepthStencilState字段。
//        学习模板缓冲区用法的最佳方式即从现存的示例应用程序着手。一旦对实例中的模板缓冲区部分有了感性的认识，我们便可以更加得心应手地运用它了。
//
//    2.深度/模板缓冲区的格式及其资源数据的清理:
//        深度/模板缓冲区其实也是一种纹理，因而必须用下列特定的数据格式来创建它。深度/模板缓冲可用的格式如下：
//            1．DXGI_FORMAT_D32_FLOAT_S8X24_UINT：此格式用一个32位浮点数来指定深度缓冲区，并以另一个32位无符号整数来指定模板缓冲区。
//                其中，无符号整数里的8位用于将模板缓冲区映射到范围[0, 255]，另外24位不可用，仅作填充占位。
//            2．DXGI_FORMAT_D24_UNORM_S8_UINT：指定一个无符号的24位深度缓冲区，并将其映射到范围[0, 1]内。另外8位（无符号整数）用于令模板缓冲区映射至范围[0,255]。
//        在D3DApp应用框架中，当要创建深度缓冲区时就要像下面那样来指定它的格式：
//            DXGI_FORMAT mDepthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
//            depthStencilDesc.Format = mDepthStencilFormat;
//        我们可以在绘制每一帧画面之初，用以下方法来重置模板缓冲区中的局部数据（也可用于清理深度缓冲区）。
//            void ID3D12GraphicsCommandList::ClearDepthStencilView( 
//                D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView,
//                D3D12_CLEAR_FLAGS ClearFlags,
//                FLOAT Depth,
//                UINT8 Stencil,
//                UINT NumRects,
//                const D3D12_RECT *pRects);
//
//    3.模板测试:
//        如前所述，我们可以通过模板缓冲区来阻止对后台缓冲区特定区域的绘制行为。而这项操作实则是由模板测试（stencil test）来决定的，它的处理过程如下：
//        if(StencilRef & StencilReadMask ◁= Value & StencilReadMask)
//            accept pixel
//        else
//            reject pixel
//        模板测试会随着像素的光栅化过程而执行（即在输出合并阶段进行）。若模板功能呈开启状态，则需经过下面两处运算。
//            1．左运算数（left-hand-side，LHS）由程序中定义的模板参考值（stencil reference value）StencilRef
//                与程序内定义的掩码值（masking value）StencilReadMask通过AND（与）运算来加以确定。 ==> (StencilRef & StencilReadMask)
//            2．右运算数（right-hand-side，RHS）由正在接受模板测试的特定像素位于模板缓冲区中的对应值Value
//                与程序中定义的掩码值StencilReadMask经过AND计算来加以确定。                       ==> (Value & StencilReadMask)
//        可以发现，左运算数与右运算数中的StencilReadMask是同一个值。接下来，模板测试用程序中所选定的比较函数（comparison function）◁= 对左运算数与右运算数进行比对，从而得到布尔类型的返回值。
//        如果测试结果为true，就将当前受检测的像素写入后台缓冲区（即假设此像素已通过深度测试）；如果测试结果为false，则禁止此像素向后台缓冲区的写操作。
//        当然，如果一个像素因模板测试失败而被丢弃，它的相关数据也不会被写入深度缓冲区。运算符 “◁= ”是D3D12_COMPARISON_FUNC枚举类型所定义的比较函数之一[1]：
//            typedef enum D3D12_COMPARISON_FUNC  (d3d12.h中注解)
//
//            ** 注：“◁= ”可理解为是对D3D12_COMPARISON_FUNC枚举类型所有比较函数的一个统称，它最终会被定义为D3D12_COMPARISON_FUNC枚举类型中的某一个比较函数, 用于模版值比较
//            ** 比如下文提到"DepthFunc:将该参数指定为枚举类型D3D12_COMPARISON_FUNC的成员之一，以此来定义深度测试所用的比较函数,此项一般被设为D3D12_COMPARISON_FUNC_LESS"
//            ** 此时: “◁= ”就等于D3D12_COMPARISON_FUNC_LESS比较函数，即“◁= ” ==> "<"
//            
//    4.描述深度/模板状态:
//        要描述深度/模板状态，就需填写D3D12_DEPTH_STENCIL_DESC实例：
//            typedef struct D3D12_DEPTH_STENCIL_DESC
//              BOOL DepthEnable; // 默认值为True
//
//              // 默认值为 D3D12_DEPTH_WRITE_MASK_ALL
//              D3D12_DEPTH_WRITE_MASK DepthWriteMask;
//
//              // 默认值为 D3D12_COMPARISON_LESS
//              D3D12_COMPARISON_FUNC DepthFunc;
//
//              BOOL StencilEnable;        // 默认值为 False
//              UINT8 StencilReadMask;     // 默认值为 0xff，即D3D12_DEFAULT_STENCIL_WRITE_MASK
//              UINT8 StencilWriteMask;    // 默认值为 0xff，即D3D12_DEFAULT_STENCIL_WRITE_MASK
//              D3D12_DEPTH_STENCILOP_DESC FrontFace; 
//              D3D12_DEPTH_STENCILOP_DESC BackFace; 
//            } D3D12_DEPTH_STENCIL_DESC;
//        1.深度信息的相关设置深度信息的相关设置如下:
//            1．DepthEnable：设置为true，则开启深度缓冲；设置为false，则禁用。当深度测试被禁止时，物体的绘制顺序就变得极为重要，否则位于遮挡物之后的像素片段也将被绘制出来（回顾4.1.5节）。
//                如果深度缓冲被禁用，则深度缓冲区中的元素便不会被更新，DepthWriteMask项的设置也不会起作用。
//            2．DepthWriteMask：可将此参数设置为D3D12_DEPTH_WRITE_MASK_ZERO或者D3D12_DEPTH_WRITE_MASK_ALL，但两者不能共存。
//                假设DepthEnable为 true，若把此参数设置为D3D12_DEPTH_WRITE_MASK_ZERO便会禁止对深度缓冲区的写操作，但仍可执行深度测试；
//                若将该项设为D3D12_DEPTH_WRITE_MASK_ALL，则通过深度测试与模板测试的深度数据将被写入深度缓冲区。这种控制深度数据读写的能力，为某些特效的实现提供了良好的契机。
//            3．DepthFunc：将该参数指定为枚举类型D3D12_COMPARISON_FUNC的成员之一，以此来定义深度测试所用的比较函数。
//                此项一般被设为D3D12_COMPARISON_FUNC_LESS，因而常常执行如4.1.5节中所述的深度测试。即，若给定像素片段的深度值小于位于深度缓冲区中对应像素的深度值，
//                则接受该像素片段（离摄像机近的物体遮挡距摄像机远的物体）。当然，也正如我们所看到的，Direct3D也允许用户根据需求来自定义深度测试。
//        2.模板信息的相关设置模板信息的相关设置如下:
//            1．StencilEnable：设置为true，则开启模板测试；设置为false，则禁用。
//            2．StencilReadMask：该项用于以下模板测试：
//                if(StencilRef & StencilReadMask ◁= Value & StencilReadMask)
//                    accept pixel
//                else
//                    reject pixel
//                若采用该项的默认值，则不会屏蔽任何一位模板值。 ==>  #define D3D12_DEFAULT_STENCIL_READ_MASK  ( 0xff )
//            3．StencilWriteMask：当模板缓冲区被更新时，我们可以通过写掩码（write mask）来屏蔽特定位的写入操作。
//                例如，如果我们希望防止前4位数据被改写，便可以将写掩码设置为0x0f。而默认配置是不会屏蔽任何一位模板值的： #define D3D12_DEFAULT_STENCIL_WRITE_MASK ( 0xff )
//            4．FrontFace：填写一个D3D12_DEPTH_STENCILOP_DESC结构体实例，以指示根据模板测试与深度测试的结果，应对正面朝向的三角形要进行何种模板运算。
//            5．BackFace：填写一个D3D12_DEPTH_STENCILOP_DESC结构体实例，以指出根据模板测试与深度测试的结果，应对背面朝向的三角形要进行何种模板运算。
//                typedef struct D3D12_DEPTH_STENCILOP_DESC {
//                 D3D12_STENCIL_OP StencilFailOp;      // 默认值为: D3D12_STENCIL_OP_KEEP
//                 D3D12_STENCIL_OP StencilDepthFailOp; // 默认值为: D3D12_STENCIL_OP_KEEP
//                 D3D12_STENCIL_OP StencilPassOp;      // 默认值为: D3D12_STENCIL_OP_KEEP
//                 D3D12_COMPARISON_FUNC StencilFunc;   // 默认值为: D3D12_COMPARISON_FUNC_ALWAYS
//                } D3D12_DEPTH_STENCILOP_DESC;
//                1．StencilFailOp：枚举类型D3D12_STENCIL_OP中的成员之一，描述了当像素片段在模板测试失败时，应该怎样更新模板缓冲区。
//                2．StencilDepthFailOp：枚举类型D3D12_STENCIL_OP中的成员之一，描述了当像素片段通过模板测试，却在深度测试失败时，应如何更新模板缓冲区。
//                3．StencilPassOp：枚举类型D3D12_STENCIL_OP中的成员之一，描述了当像素片段通过模板测试与深度测试时，该怎样更新模板缓冲区。
//                4．StencilFunc：枚举类型D3D12_COMPARISON_FUNC中的成员之一，定义了模板测试所用的比较函数。
//                    typedef 
//                    enum D3D12_STENCIL_OP
//                    {
//                      D3D12_STENCIL_OP_KEEP      = 1,
//                      D3D12_STENCIL_OP_ZERO      = 2,
//                      D3D12_STENCIL_OP_REPLACE   = 3,
//                      D3D12_STENCIL_OP_INCR_SAT  = 4,
//                      D3D12_STENCIL_OP_DECR_SAT  = 5,
//                      D3D12_STENCIL_OP_INVERT    = 6,
//                      D3D12_STENCIL_OP_INCR      = 7,
//                      D3D12_STENCIL_OP_DECR      = 8
//                    } D3D12_STENCIL_OP;
//                    1．D3D12_STENCIL_OP_KEEP：不修改模板缓冲区，即保持当前的数据。
//                    2．D3D12_STENCIL_OP_ZERO：将模板缓冲区中的元素设置为0。
//                    3．D3D12_STENCIL_OP_REPLACE：将模板缓冲区中的元素替换为用于模板测试的模板参考值（StencilRef）。注意，只有当我们将深度/模板缓冲区状态块绑定到渲染流水线时，才能够设定StencilRef值（见11.3.3节）。
//                    4．D3D12_STENCIL_OP_INCR_SAT：对模板缓冲区中的元素进行递增（increment）操作。如果递增值超出最大值（例如，8位模板缓冲区的最大值为255），则将此模板缓冲区元素限定为最大值。
//                    5．D3D12_STENCIL_OP_DECR_SAT：对模板缓冲区中的元素进行递减（decrement）操作。如果递减值小于0，则将该模板缓冲区元素限定为0。
//                    6．D3D12_STENCIL_OP_INVERT：对模板缓冲区中的元素数据按二进制位进行反转。
//                    7．D3D12_STENCIL_OP_INCR：对模板缓冲区中的元素进行递增操作。如果递增值超出最大值（例如，对于8位模板缓冲区而言，其最大值为255），则环回至0。
//                    8．D3D12_STENCIL_OP_DECR：对模板缓冲区中的元素进行递减操作。如果递减值小于0，则环回至可取到的最大值。
//
//                **注意:通过观察能够看出，对正面朝向三角形与背面朝向三角形所进行的模板运算可以是互不相同的。由于在执行背面剔除后背面朝向的多边形并不会得到渲染，
//                    所以在这种情况下对BackFace的设置便是无足轻重的。然而，我们有时候却需要针对特定的图形学算法或透明几何体（例如铁丝网盒，我们能透过它看到其背后的面）
//                    的处理来渲染背面朝向的多边形。而此时对BackFace的设置则又变得特别重要。
//    
//    5.创建和绑定深度/模板状态
//        一旦将描述深度/模板状态的D3D12_DEPTH_STENCIL_DESC实例填写完整，我们就可以将其赋予PSO的D3D12_GRAPHICS_PIPELINE_STATE_DESC::DepthStencilState字段。
//        而使用此PSO绘制的几何体，都将根据上述的深度/模板设置来进行渲染。有一个细节我们还未曾提及，即如何来设置模板参考值。
//        此操作可由ID3D12GraphicsCommandList::OMSetStencilRef方法来实现，它以一个无符号整数作为参数。例如，下列代码将模板参考值设置为1：
//        mCommandList->OMSetStencilRef(1);
//
//小结:
//    模板缓冲区是一种离屏缓冲区，我们可以通过它来阻止特定像素片段向后台缓冲区的渲染操作。
//    由于模板缓冲区与深度缓冲区分辨率相同，所以两者可以联合使用。
//    深度/模板缓冲区的有效格式为DXGI_FORMAT_D32_FLOAT_S8X24_UINT与DXGI_FORMAT_D24_UNORM_S8_UINT。
//
//*/
//
//#include "../../../Common/d3dApp.h"
//#include "../../../Common/MathHelper.h"
//#include "../../../Common/UploadBuffer.h"
//#include "../../../Common/GeometryGenerator.h"
//#include "StencilFrameResource.h"
//
//using Microsoft::WRL::ComPtr;
//using namespace DirectX;
//using namespace DirectX::PackedVector;
//
//#pragma comment(lib, "d3dcompiler.lib")
//#pragma comment(lib, "D3D12.lib")
//
//const int gNumFrameResources = 3;
//
//// Lightweight structure stores parameters to draw a shape.  This will
//// vary from app-to-app.
//struct RenderItem
//{
//	RenderItem() = default;
//
//    // World matrix of the shape that describes the object's local space
//    // relative to the world space, which defines the position, orientation,
//    // and scale of the object in the world.
//    XMFLOAT4X4 World = MathHelper::Identity4x4();
//
//	XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
//
//	// Dirty flag indicating the object data has changed and we need to update the constant buffer.
//	// Because we have an object cbuffer for each FrameResource, we have to apply the
//	// update to each FrameResource.  Thus, when we modify obect data we should set 
//	// NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
//	int NumFramesDirty = gNumFrameResources;
//
//	// Index into GPU constant buffer corresponding to the ObjectCB for this render item.
//	UINT ObjCBIndex = -1;
//
//	Material* Mat = nullptr;
//	MeshGeometry* Geo = nullptr;
//
//    // Primitive topology.
//    D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
//
//    // DrawIndexedInstanced parameters.
//    UINT IndexCount = 0;
//    UINT StartIndexLocation = 0;
//    int BaseVertexLocation = 0;
//};
//
//enum class RenderLayer : int
//{
//	Opaque = 0,
//	Mirrors ,
//	Reflected,
//	Transparent,
//	Shadow,
//	Count
//};
//
//class StencilApp : public D3DApp
//{
//public:
//    StencilApp(HINSTANCE hInstance);
//    StencilApp(const StencilApp& rhs) = delete;
//    StencilApp& operator=(const StencilApp& rhs) = delete;
//    ~StencilApp();
//
//    virtual bool Initialize()override;
//
//private:
//    virtual void OnResize()override;
//    virtual void Update(const GameTimer& gt)override;
//    virtual void Draw(const GameTimer& gt)override;
//
//    virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
//    virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
//    virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
//
//    void OnKeyboardInput(const GameTimer& gt);
//	void UpdateCamera(const GameTimer& gt);
//	void AnimateMaterials(const GameTimer& gt);
//	void UpdateObjectCBs(const GameTimer& gt);
//	void UpdateMaterialCBs(const GameTimer& gt);
//	void UpdateMainPassCB(const GameTimer& gt);
//	void UpdateReflectedPassCB(const GameTimer& gt);
//
//	void LoadTextures();
//    void BuildRootSignature();
//	void BuildDescriptorHeaps();
//    void BuildShadersAndInputLayout();
//    void BuildRoomGeometry();
//	void BuildSkullGeometry();
//    void BuildPSOs();
//    void BuildFrameResources();
//    void BuildMaterials();
//    void BuildRenderItems();
//    void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
//
//	std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
//
//private:
//
//    std::vector<std::unique_ptr<StencilFrameResource>> mFrameResources;
//    StencilFrameResource* mCurrFrameResource = nullptr;
//    int mCurrFrameResourceIndex = 0;
//
//    UINT mCbvSrvDescriptorSize = 0;
//
//    ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
//
//	ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
//
//	std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
//	std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
//	std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
//	std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
//	std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
//
//    std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
//
//	// Cache render items of interest.
//	RenderItem* mSkullRitem = nullptr;
//	RenderItem* mReflectedSkullRitem = nullptr;
//	RenderItem* mShadowedSkullRitem = nullptr;
//
//	// List of all the render items.
//	std::vector<std::unique_ptr<RenderItem>> mAllRitems;
//
//	// Render items divided by PSO.
//	std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
//
//    PassConstants mMainPassCB;
//	PassConstants mReflectedPassCB;
//
//	XMFLOAT3 mSkullTranslation = { 0.0f, 1.0f, -5.0f };
//
//	XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
//	XMFLOAT4X4 mView = MathHelper::Identity4x4();
//	XMFLOAT4X4 mProj = MathHelper::Identity4x4();
//
//    float mTheta = 1.24f*XM_PI;
//    float mPhi = 0.42f*XM_PI;
//    float mRadius = 12.0f;
//
//    POINT mLastMousePos;
//};
//
//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
//    PSTR cmdLine, int showCmd)
//{
//    // Enable run-time memory check for debug builds.
//#if defined(DEBUG) | defined(_DEBUG)
//    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
//#endif
//
//    try
//    {
//        StencilApp theApp(hInstance);
//        if(!theApp.Initialize())
//            return 0;
//
//        return theApp.Run();
//    }
//    catch(DxException& e)
//    {
//        MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
//        return 0;
//    }
//}
//
//StencilApp::StencilApp(HINSTANCE hInstance)
//    : D3DApp(hInstance)
//{
//}
//
//StencilApp::~StencilApp()
//{
//    if(md3dDevice != nullptr)
//        FlushCommandQueue();
//}
//
//bool StencilApp::Initialize()
//{
//    if(!D3DApp::Initialize())
//        return false;
//
//    // Reset the command list to prep for initialization commands.
//    ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
//
//    // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
//	// so we have to query this information.
//    mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
//
//	LoadTextures();
//    BuildRootSignature();
//	BuildDescriptorHeaps();
//    BuildShadersAndInputLayout();
//    BuildRoomGeometry();
//	BuildSkullGeometry();
//	BuildMaterials();
//    BuildRenderItems();
//    BuildFrameResources();
//    BuildPSOs();
//
//    // Execute the initialization commands.
//    ThrowIfFailed(mCommandList->Close());
//    ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
//    mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
//
//    // Wait until initialization is complete.
//    FlushCommandQueue();
//
//    return true;
//}
// 
//void StencilApp::OnResize()
//{
//    D3DApp::OnResize();
//
//    // The window resized, so update the aspect ratio and recompute the projection matrix.
//    XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
//    XMStoreFloat4x4(&mProj, P);
//}
//
//void StencilApp::Update(const GameTimer& gt)
//{
//    OnKeyboardInput(gt);
//	UpdateCamera(gt);
//
//    // Cycle through the circular frame resource array.
//    mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
//    mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
//
//    // Has the GPU finished processing the commands of the current frame resource?
//    // If not, wait until the GPU has completed commands up to this fence point.
//    if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
//    {
//        HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
//        ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
//        WaitForSingleObject(eventHandle, INFINITE);
//        CloseHandle(eventHandle);
//    }
//
//	AnimateMaterials(gt);
//	UpdateObjectCBs(gt);
//	UpdateMaterialCBs(gt);
//	UpdateMainPassCB(gt);
//	UpdateReflectedPassCB(gt);
//}
//
//void StencilApp::Draw(const GameTimer& gt)
//{
//    auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
//
//    // Reuse the memory associated with command recording.
//    // We can only reset when the associated command lists have finished execution on the GPU.
//    ThrowIfFailed(cmdListAlloc->Reset());
//
//    // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
//    // Reusing the command list reuses memory.
//    ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
//
//    mCommandList->RSSetViewports(1, &mScreenViewport);
//    mCommandList->RSSetScissorRects(1, &mScissorRect);
//
//    // Indicate a state transition on the resource usage.
//	mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
//		D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
//
//    // Clear the back buffer and depth buffer.
//    mCommandList->ClearRenderTargetView(CurrentBackBufferView(), (float*)&mMainPassCB.FogColor, 0, nullptr);
//    mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
//
//    // Specify the buffers we are going to render to.
//    mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
//
//	ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
//	mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
//
//	mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
//
//	UINT passCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(PassConstants));
//
//	// Draw opaque items--floors, walls, skull.
//    // 绘制不透明的物体——地板、墙壁、骷髅头
//	auto passCB = mCurrFrameResource->PassCB->Resource();
//	mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
//    DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
//	
//	// Mark the visible mirror pixels in the stencil buffer with the value 1
//    // 将模板缓冲区中可见的镜面像素标记为1
//	mCommandList->OMSetStencilRef(1);
//	mCommandList->SetPipelineState(mPSOs["markStencilMirrors"].Get());
//	DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Mirrors]);
//
//	// Draw the reflection into the mirror only (only for pixels where the stencil buffer is 1).
//	// Note that we must supply a different per-pass constant buffer--one with the lights reflected.
//    // 只绘制镜子范围内的镜像（即仅绘制模板缓冲区中标记为1的像素）
//    // 注意，我们必须使用两个单独的渲染过程常量缓冲区（per-pass constant buffer）来完成此工作，
//    // 一个存储物体镜像，另一个保存光照镜像
//	mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress() + 1 * passCBByteSize);
//	mCommandList->SetPipelineState(mPSOs["drawStencilReflections"].Get());
//	DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Reflected]);
//
//	// Restore main pass constants and stencil ref.
//    // 恢复主渲染过程常量数据以及模板参考值
//	mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
//	mCommandList->OMSetStencilRef(0);
//
//	// Draw mirror with transparency so reflection blends through.
//    // 绘制透明的镜面，使镜像可以与之混合
//	mCommandList->SetPipelineState(mPSOs["transparent"].Get());
//	DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Transparent]);
//
//	// Draw shadows
//	mCommandList->SetPipelineState(mPSOs["shadow"].Get());
//	DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Shadow]);
//	
//    // Indicate a state transition on the resource usage.
//	mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
//		D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
//
//    // Done recording commands.
//    ThrowIfFailed(mCommandList->Close());
//
//    // Add the command list to the queue for execution.
//    ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
//    mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
//
//    // Swap the back and front buffers
//    ThrowIfFailed(mSwapChain->Present(0, 0));
//	mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
//
//    // Advance the fence value to mark commands up to this fence point.
//    mCurrFrameResource->Fence = ++mCurrentFence;
//
//    // Notify the fence when the GPU completes commands up to this fence point.
//    mCommandQueue->Signal(mFence.Get(), mCurrentFence);
//}
//
//void StencilApp::OnMouseDown(WPARAM btnState, int x, int y)
//{
//    mLastMousePos.x = x;
//    mLastMousePos.y = y;
//
//    SetCapture(mhMainWnd);
//}
//
//void StencilApp::OnMouseUp(WPARAM btnState, int x, int y)
//{
//    ReleaseCapture();
//}
//
//void StencilApp::OnMouseMove(WPARAM btnState, int x, int y)
//{
//    if((btnState & MK_LBUTTON) != 0)
//    {
//        // Make each pixel correspond to a quarter of a degree.
//        float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
//        float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
//
//        // Update angles based on input to orbit camera around box.
//        mTheta += dx;
//        mPhi += dy;
//
//        // Restrict the angle mPhi.
//        mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
//    }
//    else if((btnState & MK_RBUTTON) != 0)
//    {
//        // Make each pixel correspond to 0.2 unit in the scene.
//        float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
//        float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
//
//        // Update the camera radius based on input.
//        mRadius += dx - dy;
//
//        // Restrict the radius.
//        mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
//    }
//
//    mLastMousePos.x = x;
//    mLastMousePos.y = y;
//}
// 
//void StencilApp::OnKeyboardInput(const GameTimer& gt)
//{
//	//
//	// Allow user to move skull.
//	//
//
//	const float dt = gt.DeltaTime();
//
//	if(GetAsyncKeyState('A') & 0x8000)
//		mSkullTranslation.x -= 1.0f*dt;
//
//	if(GetAsyncKeyState('D') & 0x8000)
//		mSkullTranslation.x += 1.0f*dt;
//
//	if(GetAsyncKeyState('W') & 0x8000)
//		mSkullTranslation.y += 1.0f*dt;
//
//	if(GetAsyncKeyState('S') & 0x8000)
//		mSkullTranslation.y -= 1.0f*dt;
//
//	// Don't let user move below ground plane.
//	mSkullTranslation.y = MathHelper::Max(mSkullTranslation.y, 0.0f);
//
//	// Update the new world matrix.
//	XMMATRIX skullRotate = XMMatrixRotationY(0.5f*MathHelper::Pi);
//	XMMATRIX skullScale = XMMatrixScaling(0.45f, 0.45f, 0.45f);
//	XMMATRIX skullOffset = XMMatrixTranslation(mSkullTranslation.x, mSkullTranslation.y, mSkullTranslation.z);
//	XMMATRIX skullWorld = skullRotate*skullScale*skullOffset;
//	XMStoreFloat4x4(&mSkullRitem->World, skullWorld);
//
//	// Update reflection world matrix.
//	XMVECTOR mirrorPlane = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); // xy plane
//	XMMATRIX R = XMMatrixReflect(mirrorPlane);
//	XMStoreFloat4x4(&mReflectedSkullRitem->World, skullWorld * R);
//
//	// Update shadow world matrix.
//    // 更新阴影的世界矩阵
//	XMVECTOR shadowPlane = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); // xz plane
//	XMVECTOR toMainLight = -XMLoadFloat3(&mMainPassCB.Lights[0].Direction);
//	XMMATRIX S = XMMatrixShadow(shadowPlane, toMainLight);
//	XMMATRIX shadowOffsetY = XMMatrixTranslation(0.0f, 0.001f, 0.0f);
//	XMStoreFloat4x4(&mShadowedSkullRitem->World, skullWorld * S * shadowOffsetY);
//
//	mSkullRitem->NumFramesDirty = gNumFrameResources;
//	mReflectedSkullRitem->NumFramesDirty = gNumFrameResources;
//	mShadowedSkullRitem->NumFramesDirty = gNumFrameResources;
//}
// 
//void StencilApp::UpdateCamera(const GameTimer& gt)
//{
//	// Convert Spherical to Cartesian coordinates.
//	mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
//	mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
//	mEyePos.y = mRadius*cosf(mPhi);
//
//	// Build the view matrix.
//	XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
//	XMVECTOR target = XMVectorZero();
//	XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
//
//	XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
//	XMStoreFloat4x4(&mView, view);
//}
//
//void StencilApp::AnimateMaterials(const GameTimer& gt)
//{
//
//}
//
//void StencilApp::UpdateObjectCBs(const GameTimer& gt)
//{
//	auto currObjectCB = mCurrFrameResource->ObjectCB.get();
//	for(auto& e : mAllRitems)
//	{
//		// Only update the cbuffer data if the constants have changed.  
//		// This needs to be tracked per frame resource.
//		if(e->NumFramesDirty > 0)
//		{
//			XMMATRIX world = XMLoadFloat4x4(&e->World);
//			XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
//
//			ObjectConstants objConstants;
//			XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
//			XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
//
//			currObjectCB->CopyData(e->ObjCBIndex, objConstants);
//
//			// Next FrameResource need to be updated too.
//			e->NumFramesDirty--;
//		}
//	}
//}
//
//void StencilApp::UpdateMaterialCBs(const GameTimer& gt)
//{
//	auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
//	for(auto& e : mMaterials)
//	{
//		// Only update the cbuffer data if the constants have changed.  If the cbuffer
//		// data changes, it needs to be updated for each FrameResource.
//		Material* mat = e.second.get();
//		if(mat->NumFramesDirty > 0)
//		{
//			XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
//
//			MaterialConstants matConstants;
//			matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
//			matConstants.FresnelR0 = mat->FresnelR0;
//			matConstants.Roughness = mat->Roughness;
//			XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));
//
//			currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
//
//			// Next FrameResource need to be updated too.
//			mat->NumFramesDirty--;
//		}
//	}
//}
//
//void StencilApp::UpdateMainPassCB(const GameTimer& gt)
//{
//	XMMATRIX view = XMLoadFloat4x4(&mView);
//	XMMATRIX proj = XMLoadFloat4x4(&mProj);
//
//	XMMATRIX viewProj = XMMatrixMultiply(view, proj);
//	XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
//	XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
//	XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
//
//	XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
//	XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
//	XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
//	XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
//	XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
//	XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
//	mMainPassCB.EyePosW = mEyePos;
//	mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
//	mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
//	mMainPassCB.NearZ = 1.0f;
//	mMainPassCB.FarZ = 1000.0f;
//	mMainPassCB.TotalTime = gt.TotalTime();
//	mMainPassCB.DeltaTime = gt.DeltaTime();
//	mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
//	mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
//	mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
//	mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
//	mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
//	mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
//	mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
//
//	// Main pass stored in index 2
//	auto currPassCB = mCurrFrameResource->PassCB.get();
//	currPassCB->CopyData(0, mMainPassCB);
//}
//
//void StencilApp::UpdateReflectedPassCB(const GameTimer& gt)
//{
//	mReflectedPassCB = mMainPassCB;
//
//	XMVECTOR mirrorPlane = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); // xy plane
//	XMMATRIX R = XMMatrixReflect(mirrorPlane);
//
//	// Reflect the lighting.
//	for(int i = 0; i < 3; ++i)
//	{
//		XMVECTOR lightDir = XMLoadFloat3(&mMainPassCB.Lights[i].Direction);
//		XMVECTOR reflectedLightDir = XMVector3TransformNormal(lightDir, R);
//		XMStoreFloat3(&mReflectedPassCB.Lights[i].Direction, reflectedLightDir);
//	}
//
//	// Reflected pass stored in index 1
//	auto currPassCB = mCurrFrameResource->PassCB.get();
//	currPassCB->CopyData(1, mReflectedPassCB);
//}
//
//void StencilApp::LoadTextures()
//{
//	auto bricksTex = std::make_unique<Texture>();
//	bricksTex->Name = "bricksTex";
//	bricksTex->Filename = L"E:/DX12Book/DX12LearnProject/DX12Learn/Textures/bricks3.dds";
//	ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
//		mCommandList.Get(), bricksTex->Filename.c_str(),
//		bricksTex->Resource, bricksTex->UploadHeap));
//
//	auto checkboardTex = std::make_unique<Texture>();
//	checkboardTex->Name = "checkboardTex";
//	checkboardTex->Filename = L"E:/DX12Book/DX12LearnProject/DX12Learn/Textures/checkboard.dds";
//	ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
//		mCommandList.Get(), checkboardTex->Filename.c_str(),
//		checkboardTex->Resource, checkboardTex->UploadHeap));
//
//	auto iceTex = std::make_unique<Texture>();
//	iceTex->Name = "iceTex";
//	iceTex->Filename = L"E:/DX12Book/DX12LearnProject/DX12Learn/Textures/ice.dds";
//	ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
//		mCommandList.Get(), iceTex->Filename.c_str(),
//		iceTex->Resource, iceTex->UploadHeap));
//
//	auto white1x1Tex = std::make_unique<Texture>();
//	white1x1Tex->Name = "white1x1Tex";
//	white1x1Tex->Filename = L"E:/DX12Book/DX12LearnProject/DX12Learn/Textures/white1x1.dds";
//	ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
//		mCommandList.Get(), white1x1Tex->Filename.c_str(),
//		white1x1Tex->Resource, white1x1Tex->UploadHeap));
//
//	mTextures[bricksTex->Name] = std::move(bricksTex);
//	mTextures[checkboardTex->Name] = std::move(checkboardTex);
//	mTextures[iceTex->Name] = std::move(iceTex);
//	mTextures[white1x1Tex->Name] = std::move(white1x1Tex);
//}
//
//void StencilApp::BuildRootSignature()
//{
//	CD3DX12_DESCRIPTOR_RANGE texTable;
//	texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
//
//    // Root parameter can be a table, root descriptor or root constants.
//    CD3DX12_ROOT_PARAMETER slotRootParameter[4];
//
//	// Perfomance TIP: Order from most frequent to least frequent.
//	slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
//    slotRootParameter[1].InitAsConstantBufferView(0);
//    slotRootParameter[2].InitAsConstantBufferView(1);
//    slotRootParameter[3].InitAsConstantBufferView(2);
//
//	auto staticSamplers = GetStaticSamplers();
//
//    // A root signature is an array of root parameters.
//	CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
//		(UINT)staticSamplers.size(), staticSamplers.data(),
//		D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
//
//    // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
//    ComPtr<ID3DBlob> serializedRootSig = nullptr;
//    ComPtr<ID3DBlob> errorBlob = nullptr;
//    HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
//        serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
//
//    if(errorBlob != nullptr)
//    {
//        ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
//    }
//    ThrowIfFailed(hr);
//
//    ThrowIfFailed(md3dDevice->CreateRootSignature(
//		0,
//        serializedRootSig->GetBufferPointer(),
//        serializedRootSig->GetBufferSize(),
//        IID_PPV_ARGS(mRootSignature.GetAddressOf())));
//}
//
//void StencilApp::BuildDescriptorHeaps()
//{
//	//
//	// Create the SRV heap.
//	//
//	D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
//	srvHeapDesc.NumDescriptors = 4;
//	srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
//	srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
//	ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
//
//	//
//	// Fill out the heap with actual descriptors.
//	//
//	CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
//
//	auto bricksTex = mTextures["bricksTex"]->Resource;
//	auto checkboardTex = mTextures["checkboardTex"]->Resource;
//	auto iceTex = mTextures["iceTex"]->Resource;
//	auto white1x1Tex = mTextures["white1x1Tex"]->Resource;
//
//	D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
//	srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
//	srvDesc.Format = bricksTex->GetDesc().Format;
//	srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
//	srvDesc.Texture2D.MostDetailedMip = 0;
//	srvDesc.Texture2D.MipLevels = -1;
//	md3dDevice->CreateShaderResourceView(bricksTex.Get(), &srvDesc, hDescriptor);
//
//	// next descriptor
//	hDescriptor.Offset(1, mCbvSrvDescriptorSize);
//
//	srvDesc.Format = checkboardTex->GetDesc().Format;
//	md3dDevice->CreateShaderResourceView(checkboardTex.Get(), &srvDesc, hDescriptor);
//
//	// next descriptor
//	hDescriptor.Offset(1, mCbvSrvDescriptorSize);
//
//	srvDesc.Format = iceTex->GetDesc().Format;
//	md3dDevice->CreateShaderResourceView(iceTex.Get(), &srvDesc, hDescriptor);
//
//	// next descriptor
//	hDescriptor.Offset(1, mCbvSrvDescriptorSize);
//
//	srvDesc.Format = white1x1Tex->GetDesc().Format;
//	md3dDevice->CreateShaderResourceView(white1x1Tex.Get(), &srvDesc, hDescriptor);
//}
//
//void StencilApp::BuildShadersAndInputLayout()
//{
//	const D3D_SHADER_MACRO defines[] =
//	{
//		"FOG", "1",
//		NULL, NULL
//	};
//
//	const D3D_SHADER_MACRO alphaTestDefines[] =
//	{
//		"FOG", "1",
//		"ALPHA_TEST", "1",
//		NULL, NULL
//	};
//
//	mShaders["standardVS"] = d3dUtil::CompileShader(L"E:\\DX12Book\\DX12LearnProject\\DX12Learn\\LearnDemo\\Chapter 11 Stenciling\\StencilDemo\\Shaders\\Default.hlsl", nullptr, "VS", "vs_5_0");
//	mShaders["opaquePS"] = d3dUtil::CompileShader(L"E:\\DX12Book\\DX12LearnProject\\DX12Learn\\LearnDemo\\Chapter 11 Stenciling\\StencilDemo\\Shaders\\Default.hlsl", defines, "PS", "ps_5_0");
//	mShaders["alphaTestedPS"] = d3dUtil::CompileShader(L"E:\\DX12Book\\DX12LearnProject\\DX12Learn\\LearnDemo\\Chapter 11 Stenciling\\StencilDemo\\Shaders\\Default.hlsl", alphaTestDefines, "PS", "ps_5_0");
//	
//    mInputLayout =
//    {
//        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
//        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
//		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
//    };
//}
//
//void StencilApp::BuildRoomGeometry()
//{
//    	// Create and specify geometry.  For this sample we draw a floor
//	// and a wall with a mirror on it.  We put the floor, wall, and
//	// mirror geometry in one vertex buffer.
//	//
//	//   |--------------|
//	//   |              |
//    //   |----|----|----|
//    //   |Wall|Mirr|Wall|
//	//   |    | or |    |
//    //   /--------------/
//    //  /   Floor      /
//	// /--------------/
//
//	std::array<Vertex, 20> vertices = 
//	{
//		// Floor: Observe we tile texture coordinates.
//		Vertex(-3.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 0.0f, 4.0f), // 0 
//		Vertex(-3.5f, 0.0f,   0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f),
//		Vertex(7.5f, 0.0f,   0.0f, 0.0f, 1.0f, 0.0f, 4.0f, 0.0f),
//		Vertex(7.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 4.0f, 4.0f),
//
//		// Wall: Observe we tile texture coordinates, and that we
//		// leave a gap in the middle for the mirror.
//		Vertex(-3.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 2.0f), // 4
//		Vertex(-3.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f),
//		Vertex(-2.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.5f, 0.0f),
//		Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.5f, 2.0f),
//
//		Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 2.0f), // 8 
//		Vertex(2.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f),
//		Vertex(7.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 2.0f, 0.0f),
//		Vertex(7.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 2.0f, 2.0f),
//
//		Vertex(-3.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f), // 12
//		Vertex(-3.5f, 6.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f),
//		Vertex(7.5f, 6.0f, 0.0f, 0.0f, 0.0f, -1.0f, 6.0f, 0.0f),
//		Vertex(7.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 6.0f, 1.0f),
//
//		// Mirror
//		Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f), // 16
//		Vertex(-2.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f),
//		Vertex(2.5f, 4.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f),
//		Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f)
//	};
//
//	std::array<std::int16_t, 30> indices = 
//	{
//		// Floor
//		0, 1, 2,	
//		0, 2, 3,
//
//		// Walls
//		4, 5, 6,
//		4, 6, 7,
//
//		8, 9, 10,
//		8, 10, 11,
//
//		12, 13, 14,
//		12, 14, 15,
//
//		// Mirror
//		16, 17, 18,
//		16, 18, 19
//	};
//
//	SubmeshGeometry floorSubmesh;
//	floorSubmesh.IndexCount = 6;
//	floorSubmesh.StartIndexLocation = 0;
//	floorSubmesh.BaseVertexLocation = 0;
//
//	SubmeshGeometry wallSubmesh;
//	wallSubmesh.IndexCount = 18;
//	wallSubmesh.StartIndexLocation = 6;
//	wallSubmesh.BaseVertexLocation = 0;
//
//	SubmeshGeometry mirrorSubmesh;
//	mirrorSubmesh.IndexCount = 6;
//	mirrorSubmesh.StartIndexLocation = 24;
//	mirrorSubmesh.BaseVertexLocation = 0;
//
//    const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
//    const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
//
//	auto geo = std::make_unique<MeshGeometry>();
//	geo->Name = "roomGeo";
//
//	ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
//	CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
//
//	ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
//	CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
//
//	geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
//		mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
//
//	geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
//		mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
//
//	geo->VertexByteStride = sizeof(Vertex);
//	geo->VertexBufferByteSize = vbByteSize;
//	geo->IndexFormat = DXGI_FORMAT_R16_UINT;
//	geo->IndexBufferByteSize = ibByteSize;
//
//	geo->DrawArgs["floor"] = floorSubmesh;
//	geo->DrawArgs["wall"] = wallSubmesh;
//	geo->DrawArgs["mirror"] = mirrorSubmesh;
//
//	mGeometries[geo->Name] = std::move(geo);
//}
//
//void StencilApp::BuildSkullGeometry()
//{
//	std::ifstream fin("E:/DX12Book/DX12LearnProject/DX12Learn/LearnDemo/Chapter 11 Stenciling/StencilDemo/Models/skull.txt");
//	
//	if(!fin)
//	{
//		MessageBox(0, L"E:/DX12Book/DX12LearnProject/DX12Learn/LearnDemo/Chapter 11 Stenciling/StencilDemo/Models/skull.txt not found.", 0, 0);
//		return;
//	}
//
//	UINT vcount = 0;
//	UINT tcount = 0;
//	std::string ignore;
//
//	fin >> ignore >> vcount;
//	fin >> ignore >> tcount;
//	fin >> ignore >> ignore >> ignore >> ignore;
//	
//	std::vector<Vertex> vertices(vcount);
//	for(UINT i = 0; i < vcount; ++i)
//	{
//		fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;
//		fin >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z;
//
//		// Model does not have texture coordinates, so just zero them out.
//		vertices[i].TexC = { 0.0f, 0.0f };
//	}
//
//	fin >> ignore;
//	fin >> ignore;
//	fin >> ignore;
//
//	std::vector<std::int32_t> indices(3 * tcount);
//	for(UINT i = 0; i < tcount; ++i)
//	{
//		fin >> indices[i*3+0] >> indices[i*3+1] >> indices[i*3+2];
//	}
//
//	fin.close();
// 
//	//
//	// Pack the indices of all the meshes into one index buffer.
//	//
// 
//	const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
//
//	const UINT ibByteSize = (UINT)indices.size() * sizeof(std::int32_t);
//
//	auto geo = std::make_unique<MeshGeometry>();
//	geo->Name = "skullGeo";
//
//	ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
//	CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
//
//	ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
//	CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
//
//	geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
//		mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
//
//	geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
//		mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
//
//	geo->VertexByteStride = sizeof(Vertex);
//	geo->VertexBufferByteSize = vbByteSize;
//	geo->IndexFormat = DXGI_FORMAT_R32_UINT;
//	geo->IndexBufferByteSize = ibByteSize;
//
//	SubmeshGeometry submesh;
//	submesh.IndexCount = (UINT)indices.size();
//	submesh.StartIndexLocation = 0;
//	submesh.BaseVertexLocation = 0;
//
//	geo->DrawArgs["skull"] = submesh;
//
//	mGeometries[geo->Name] = std::move(geo);
//}
//
//void StencilApp::BuildPSOs()
//{
//    D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
//
//	//
//	// PSO for opaque objects.
//	//
//    ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
//	opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
//	opaquePsoDesc.pRootSignature = mRootSignature.Get();
//	opaquePsoDesc.VS = 
//	{ 
//		reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
//		mShaders["standardVS"]->GetBufferSize()
//	};
//	opaquePsoDesc.PS = 
//	{ 
//		reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
//		mShaders["opaquePS"]->GetBufferSize()
//	};
//	opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
//	opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
//	opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
//	opaquePsoDesc.SampleMask = UINT_MAX;
//	opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
//	opaquePsoDesc.NumRenderTargets = 1;
//	opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
//	opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
//	opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
//	opaquePsoDesc.DSVFormat = mDepthStencilFormat;
//    ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
//
//	//
//	// PSO for transparent objects
//	//
//
//	D3D12_GRAPHICS_PIPELINE_STATE_DESC transparentPsoDesc = opaquePsoDesc;
//
//	D3D12_RENDER_TARGET_BLEND_DESC transparencyBlendDesc;
//	transparencyBlendDesc.BlendEnable = true;
//	transparencyBlendDesc.LogicOpEnable = false;
//	transparencyBlendDesc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
//	transparencyBlendDesc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
//	transparencyBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
//	transparencyBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
//	transparencyBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
//	transparencyBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
//	transparencyBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
//	transparencyBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
//
//	transparentPsoDesc.BlendState.RenderTarget[0] = transparencyBlendDesc;
//	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&transparentPsoDesc, IID_PPV_ARGS(&mPSOs["transparent"])));
//
//    /*
//        镜面效果:
//        1．将地板、墙壁以及骷髅头实物照常渲染到后台缓冲区内（不包括镜子）。注意，此步骤不修改模板缓冲区。
//        2．清理模板缓冲区，将其整体置零。图11.3展示了此时的后台缓冲区与模板缓冲区中的情况（为了简单起见，这里用立方体替代骷髅头实物）。
//        3．仅将镜面渲染到模板缓冲区中。若要禁止其他颜色数据写入到后台缓冲区，可用下列设置所创建的混合状态：
//            mirrorBlendState.RenderTarget[0].RenderTargetWriteMask = 0;
//            仅将镜面渲染到模板缓冲区中。若要禁止其他颜色数据写入到后台缓冲区，可用下列设置所创建的混合状态：
//            D3D12_DEPTH_STENCIL_DESC::DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
//
//            在向模板缓冲区渲染镜面的时候，我们将模板测试设置为每次都成功（D3D12_COMPARISON_FUNC_ALWAYS），并且在通过测试时用1（StencilRef模板参考值）来替换
//            （通过D3D12_STENCIL_OP_REPLACE来设置）模板缓冲区元素。如果深度测试失败（这是有可能发生的，例如当骷髅头遮住部分镜子的时候），
//            则应当采用枚举项D3D12_STENCIL_OP_KEEP，使模板缓冲区中的对应像素保持不变。由于仅向模板缓冲区绘制了镜面，因此在模板缓冲区内，除了镜面可见部分的对应像素为1，其他像素皆为0。
//            图11.4所示的即为更新后的模板缓冲区。换言之，我们其实就是在模板缓冲区中标记了镜面的可见像素而已。
//        4．现在我们来将骷髅头的镜像渲染至后台缓冲区及模板缓冲区中。前面曾提到，只有通过模板测试的像素才能渲染至后台缓冲区。
//            对此，我们便将其设置为：仅当模板缓冲区中的值为1时，才能通过模板测试。这可以通过令StencilRef为1，且模板运算符为D3D12_COMPARISON_FUNC_EQUAL来实现。
//            如此一来，只有模板缓冲区中元素数值为1的骷髅头镜像部分才能得以渲染。由于只有镜面可见部分所对应的模板缓冲区中元素数值为1，所以仅有这一范围内的骷髅头镜像才能被渲染出来。
//        5．最后，我们像往常那样将镜面渲染到后台缓冲区中。但是，为了能“透过”镜面观察骷髅头的镜像（它实际位于镜子的背面。虽说展现的是镜面内的镜像，但实际上是镜面背后的反射实物与镜面透明混合所得到的效果），
//            我们就需要运用透明混合技术来渲染镜面。若非如此，则由于骷髅头镜像的深度值小于镜面的深度值，理所当然地会致使骷髅头镜像被镜子挡住。
//            为此，我们只需为镜面定义一个新的材质配置实例：将其漫反射alpha通道分量设为0.3，使镜子的不透明度达到30%，并按第10.5.4小节中所述的透明混合状态来渲染镜面。
//               auto icemirror = std::make_unique<Material>();
//               icemirror->Name = "icemirror";
//               icemirror->MatCBIndex = 2;
//               icemirror->DiffuseSrvHeapIndex = 2;
//               icemirror->DiffuseAlbedo = xmFLOAT(1.0f,1.0f,1.0f,0.3f);
//               icemirror->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
//               icemirror->Roughness = 0.5f;
//
//    */
//	//
//	// PSO for marking stencil mirrors. 用于标记模板缓冲区中镜面部分的PSO
//	//
//
//    // 禁止对渲染目标的写操作
//	CD3DX12_BLEND_DESC mirrorBlendState(D3D12_DEFAULT);
//    // 仅将镜面渲染到模板缓冲区中。若要禁止其他颜色数据写入到后台缓冲区，可用下列设置所创建的混合状态：
//	mirrorBlendState.RenderTarget[0].RenderTargetWriteMask = 0;
//
//	D3D12_DEPTH_STENCIL_DESC mirrorDSS;
//	mirrorDSS.DepthEnable = true;
//	mirrorDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
//	mirrorDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
//	mirrorDSS.StencilEnable = true;
//	mirrorDSS.StencilReadMask = 0xff;
//	mirrorDSS.StencilWriteMask = 0xff;
//	
//	mirrorDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
//	mirrorDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
//	mirrorDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
//	mirrorDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
//
//	// We are not rendering backfacing polygons, so these settings do not matter.
//	mirrorDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
//	mirrorDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
//	mirrorDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
//	mirrorDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
//
//	D3D12_GRAPHICS_PIPELINE_STATE_DESC markMirrorsPsoDesc = opaquePsoDesc;
//	markMirrorsPsoDesc.BlendState = mirrorBlendState;
//	markMirrorsPsoDesc.DepthStencilState = mirrorDSS;
//	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&markMirrorsPsoDesc, IID_PPV_ARGS(&mPSOs["markStencilMirrors"])));
//
//	//
//	// PSO for stencil reflections. 用于渲染模板缓冲区中反射镜像的PSO
//	//
//
//	D3D12_DEPTH_STENCIL_DESC reflectionsDSS;
//	reflectionsDSS.DepthEnable = true;
//	reflectionsDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
//	reflectionsDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
//	reflectionsDSS.StencilEnable = true;
//	reflectionsDSS.StencilReadMask = 0xff;
//	reflectionsDSS.StencilWriteMask = 0xff;
//
//	reflectionsDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
//	reflectionsDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
//	reflectionsDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
//	reflectionsDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
//
//	// We are not rendering backfacing polygons, so these settings do not matter.
//    // 我们不渲染背面朝向的多边形，因而对这些参数的设置并不关心
//	reflectionsDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
//	reflectionsDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
//	reflectionsDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
//	reflectionsDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
//
//	D3D12_GRAPHICS_PIPELINE_STATE_DESC drawReflectionsPsoDesc = opaquePsoDesc;
//	drawReflectionsPsoDesc.DepthStencilState = reflectionsDSS;
//	drawReflectionsPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
//	drawReflectionsPsoDesc.RasterizerState.FrontCounterClockwise = true;
//	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&drawReflectionsPsoDesc, IID_PPV_ARGS(&mPSOs["drawStencilReflections"])));
//
//	//
//	// PSO for shadow objects 用于物体平面隐影的PSO
//	//
//
//	// We are going to draw shadows with transparency, so base it off the transparency description.
//    // 我们将绘制具有透明度的阴影，因此以透明度描述为基础。
//	D3D12_DEPTH_STENCIL_DESC shadowDSS;
//	shadowDSS.DepthEnable = true;
//	shadowDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
//	shadowDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
//	shadowDSS.StencilEnable = true;
//	shadowDSS.StencilReadMask = 0xff;
//	shadowDSS.StencilWriteMask = 0xff;
//
//	shadowDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
//	shadowDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
//	shadowDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
//	shadowDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
//
//	// We are not rendering backfacing polygons, so these settings do not matter.
//    // 我们这里不对背面朝向的多边形进行渲染，因而这些配置是无足轻重的
//	shadowDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
//	shadowDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
//	shadowDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
//	shadowDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
//
//	D3D12_GRAPHICS_PIPELINE_STATE_DESC shadowPsoDesc = transparentPsoDesc;
//	shadowPsoDesc.DepthStencilState = shadowDSS;
//	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&shadowPsoDesc, IID_PPV_ARGS(&mPSOs["shadow"])));
//}
//
//void StencilApp::BuildFrameResources()
//{
//    for(int i = 0; i < gNumFrameResources; ++i)
//    {
//        mFrameResources.push_back(std::make_unique<StencilFrameResource>(md3dDevice.Get(),
//            2, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
//    }
//}
//
//void StencilApp::BuildMaterials()
//{
//	auto bricks = std::make_unique<Material>();
//	bricks->Name = "bricks";
//	bricks->MatCBIndex = 0;
//	bricks->DiffuseSrvHeapIndex = 0;
//	bricks->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
//	bricks->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
//	bricks->Roughness = 0.25f;
//
//	auto checkertile = std::make_unique<Material>();
//	checkertile->Name = "checkertile";
//	checkertile->MatCBIndex = 1;
//	checkertile->DiffuseSrvHeapIndex = 1;
//	checkertile->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
//	checkertile->FresnelR0 = XMFLOAT3(0.07f, 0.07f, 0.07f);
//	checkertile->Roughness = 0.3f;
//
//	auto icemirror = std::make_unique<Material>();
//	icemirror->Name = "icemirror";
//	icemirror->MatCBIndex = 2;
//	icemirror->DiffuseSrvHeapIndex = 2;
//	icemirror->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.3f);
//	icemirror->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
//	icemirror->Roughness = 0.5f;
//
//	auto skullMat = std::make_unique<Material>();
//	skullMat->Name = "skullMat";
//	skullMat->MatCBIndex = 3;
//	skullMat->DiffuseSrvHeapIndex = 3;
//	skullMat->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
//	skullMat->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
//	skullMat->Roughness = 0.3f;
//
//	auto shadowMat = std::make_unique<Material>();
//	shadowMat->Name = "shadowMat";
//	shadowMat->MatCBIndex = 4;
//	shadowMat->DiffuseSrvHeapIndex = 3;
//	shadowMat->DiffuseAlbedo = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.5f);
//	shadowMat->FresnelR0 = XMFLOAT3(0.001f, 0.001f, 0.001f);
//	shadowMat->Roughness = 0.0f;
//
//	mMaterials["bricks"] = std::move(bricks);
//	mMaterials["checkertile"] = std::move(checkertile);
//	mMaterials["icemirror"] = std::move(icemirror);
//	mMaterials["skullMat"] = std::move(skullMat);
//	mMaterials["shadowMat"] = std::move(shadowMat);
//}
//
//void StencilApp::BuildRenderItems()
//{
//	auto floorRitem = std::make_unique<RenderItem>();
//	floorRitem->World = MathHelper::Identity4x4();
//	floorRitem->TexTransform = MathHelper::Identity4x4();
//	floorRitem->ObjCBIndex = 0;
//	floorRitem->Mat = mMaterials["checkertile"].get();
//	floorRitem->Geo = mGeometries["roomGeo"].get();
//	floorRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
//	floorRitem->IndexCount = floorRitem->Geo->DrawArgs["floor"].IndexCount;
//	floorRitem->StartIndexLocation = floorRitem->Geo->DrawArgs["floor"].StartIndexLocation;
//	floorRitem->BaseVertexLocation = floorRitem->Geo->DrawArgs["floor"].BaseVertexLocation;
//	mRitemLayer[(int)RenderLayer::Opaque].push_back(floorRitem.get());
//
//    auto wallsRitem = std::make_unique<RenderItem>();
//	wallsRitem->World = MathHelper::Identity4x4();
//	wallsRitem->TexTransform = MathHelper::Identity4x4();
//	wallsRitem->ObjCBIndex = 1;
//	wallsRitem->Mat = mMaterials["bricks"].get();
//	wallsRitem->Geo = mGeometries["roomGeo"].get();
//	wallsRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
//	wallsRitem->IndexCount = wallsRitem->Geo->DrawArgs["wall"].IndexCount;
//	wallsRitem->StartIndexLocation = wallsRitem->Geo->DrawArgs["wall"].StartIndexLocation;
//	wallsRitem->BaseVertexLocation = wallsRitem->Geo->DrawArgs["wall"].BaseVertexLocation;
//	mRitemLayer[(int)RenderLayer::Opaque].push_back(wallsRitem.get());
//
//	auto skullRitem = std::make_unique<RenderItem>();
//	skullRitem->World = MathHelper::Identity4x4();
//	skullRitem->TexTransform = MathHelper::Identity4x4();
//	skullRitem->ObjCBIndex = 2;
//	skullRitem->Mat = mMaterials["skullMat"].get();
//	skullRitem->Geo = mGeometries["skullGeo"].get();
//	skullRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
//	skullRitem->IndexCount = skullRitem->Geo->DrawArgs["skull"].IndexCount;
//	skullRitem->StartIndexLocation = skullRitem->Geo->DrawArgs["skull"].StartIndexLocation;
//	skullRitem->BaseVertexLocation = skullRitem->Geo->DrawArgs["skull"].BaseVertexLocation;
//	mSkullRitem = skullRitem.get();
//	mRitemLayer[(int)RenderLayer::Opaque].push_back(skullRitem.get());
//
//	// Reflected skull will have different world matrix, so it needs to be its own render item.
//	auto reflectedSkullRitem = std::make_unique<RenderItem>();
//	*reflectedSkullRitem = *skullRitem;
//	reflectedSkullRitem->ObjCBIndex = 3;
//	mReflectedSkullRitem = reflectedSkullRitem.get();
//	mRitemLayer[(int)RenderLayer::Reflected].push_back(reflectedSkullRitem.get());
//
//	// Shadowed skull will have different world matrix, so it needs to be its own render item.
//	auto shadowedSkullRitem = std::make_unique<RenderItem>();
//	*shadowedSkullRitem = *skullRitem;
//	shadowedSkullRitem->ObjCBIndex = 4;
//	shadowedSkullRitem->Mat = mMaterials["shadowMat"].get();
//	mShadowedSkullRitem = shadowedSkullRitem.get();
//	mRitemLayer[(int)RenderLayer::Shadow].push_back(shadowedSkullRitem.get());
//
//	auto mirrorRitem = std::make_unique<RenderItem>();
//	mirrorRitem->World = MathHelper::Identity4x4();
//	mirrorRitem->TexTransform = MathHelper::Identity4x4();
//	mirrorRitem->ObjCBIndex = 5;
//	mirrorRitem->Mat = mMaterials["icemirror"].get();
//	mirrorRitem->Geo = mGeometries["roomGeo"].get();
//	mirrorRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
//	mirrorRitem->IndexCount = mirrorRitem->Geo->DrawArgs["mirror"].IndexCount;
//	mirrorRitem->StartIndexLocation = mirrorRitem->Geo->DrawArgs["mirror"].StartIndexLocation;
//	mirrorRitem->BaseVertexLocation = mirrorRitem->Geo->DrawArgs["mirror"].BaseVertexLocation;
//	mRitemLayer[(int)RenderLayer::Mirrors].push_back(mirrorRitem.get());
//	mRitemLayer[(int)RenderLayer::Transparent].push_back(mirrorRitem.get());
//
//	mAllRitems.push_back(std::move(floorRitem));
//	mAllRitems.push_back(std::move(wallsRitem));
//	mAllRitems.push_back(std::move(skullRitem));
//	mAllRitems.push_back(std::move(reflectedSkullRitem));
//	mAllRitems.push_back(std::move(shadowedSkullRitem));
//	mAllRitems.push_back(std::move(mirrorRitem));
//}
//
//void StencilApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
//{
//    UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
//    UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
//
//	auto objectCB = mCurrFrameResource->ObjectCB->Resource();
//	auto matCB = mCurrFrameResource->MaterialCB->Resource();
//
//    // For each render item...
//    for(size_t i = 0; i < ritems.size(); ++i)
//    {
//        auto ri = ritems[i];
//
//        cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
//        cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
//        cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
//
//		CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
//		tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
//
//        D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
//		D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
//
//		cmdList->SetGraphicsRootDescriptorTable(0, tex);
//        cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);
//        cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);
//
//        cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
//    }
//}
//
//std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> StencilApp::GetStaticSamplers()
//{
//	// Applications usually only need a handful of samplers.  So just define them all up front
//	// and keep them available as part of the root signature.  
//
//	const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
//		0, // shaderRegister
//		D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
//
//	const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
//		1, // shaderRegister
//		D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
//
//	const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
//		2, // shaderRegister
//		D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
//
//	const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
//		3, // shaderRegister
//		D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
//
//	const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
//		4, // shaderRegister
//		D3D12_FILTER_ANISOTROPIC, // filter
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
//		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
//		0.0f,                             // mipLODBias
//		8);                               // maxAnisotropy
//
//	const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
//		5, // shaderRegister
//		D3D12_FILTER_ANISOTROPIC, // filter
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
//		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
//		0.0f,                              // mipLODBias
//		8);                                // maxAnisotropy
//
//	return { 
//		pointWrap, pointClamp,
//		linearWrap, linearClamp, 
//		anisotropicWrap, anisotropicClamp };
//}
